package com.gitee.srurl.system.util;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.core.util.URLUtil;
import com.gitee.srurl.core.util.AssertUtil;
import com.gitee.srurl.system.exception.WebWriteException;
import jakarta.servlet.http.HttpServletResponse;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;

import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.Charset;
import java.util.Map;

/**
 * web写入流数据工具
 *
 * @author zxw
 * @date 2023/1/3 下午10:36
 */
@Slf4j
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public abstract class WebWriteUtil {

    public static final String FILE_NAME_KEY = "Content-Disposition";

    /**
     * 下载文件 文件名记得url编码
     */
    public static final String DOWNLOAD_FILE_NAME_VALUE_PREFIX = "attachment; filename={}";

    /**
     * 预览文件 文件名记得url编码
     */
    public static final String PREVIEW_FILE_NAME_VALUE_PREFIX = "inline; filename={}";

    public static final String ACCESS_CONTROL_ALLOW_ORIGIN = "Access-Control-Allow-Origin";

    public static final String ACCESS_CONTROL_EXPOSE_HEADERS = "Access-Control-Expose-Headers";

    /**
     * 写入数据 默认下载模式
     *
     * @param response response
     * @param data     待写入的数据
     * @param filename 文件名
     */
    public static void write(HttpServletResponse response, byte[] data, String filename) {

        write(response, data, filename, false);
    }

    /**
     * 写入数据 默认下载模式
     *
     * @param response    response
     * @param inputStream 输入流
     * @param filename    文件名
     */
    public static void write(HttpServletResponse response, InputStream inputStream, String filename) {

        write(response, inputStream, filename, false);
    }

    /**
     * 写入数据
     *
     * @param response response
     * @param data     待写入的数据
     * @param filename 文件名
     * @param preview  是否预览
     */
    public static void write(HttpServletResponse response, byte[] data, String filename, boolean preview) {

        write(response, data, filename, preview, null);
    }

    /**
     * 写入数据
     *
     * @param response    response
     * @param inputStream 输入流
     * @param filename    文件名
     * @param preview     是否预览
     */
    public static void write(HttpServletResponse response, InputStream inputStream, String filename, boolean preview) {

        write(response, inputStream, filename, preview, null);
    }

    /**
     * 写入数据
     *
     * @param response response
     * @param data     待写入的数据
     * @param filename 文件名
     * @param preview  是否预览
     * @param header   自定义header参数 会覆盖目前这些设置的参数
     */
    public static void write(HttpServletResponse response,
                             byte[] data,
                             String filename,
                             boolean preview,
                             Map<String, String> header) {

        AssertUtil.nonNull(response, "response 参数不能为空！");
        AssertUtil.notEmpty(data, "写入参数不能为空！");
        AssertUtil.notBlank(filename, "文件名不能为空！");

        final String contentDisposition = preview ? PREVIEW_FILE_NAME_VALUE_PREFIX : DOWNLOAD_FILE_NAME_VALUE_PREFIX;
        response.reset();
        response.addHeader(ACCESS_CONTROL_ALLOW_ORIGIN, "*");
        response.addHeader(ACCESS_CONTROL_EXPOSE_HEADERS, "Content-Disposition");
        response.setHeader(FILE_NAME_KEY, StrUtil.format(contentDisposition, URLUtil.encode(filename, Charset.defaultCharset())));
        response.addHeader("Content-Length", "" + data.length);
        response.setContentType("application/octet-stream; charset=UTF-8");

        if (CollectionUtil.isNotEmpty(header)) {
            for (Map.Entry<String, String> e : header.entrySet()) {
                response.addHeader(e.getKey(), e.getValue());
            }
        }

        try {
            IoUtil.write(response.getOutputStream(), false, data);
        } catch (IOException e) {
            log.error("写入文件流信息异常：", e);
            throw new WebWriteException();
        }
    }

    /**
     * 写入数据
     *
     * @param response    response
     * @param inputStream 输入流
     * @param filename    文件名
     * @param preview     是否预览
     * @param header      自定义header参数 会覆盖目前这些设置的参数
     */
    public static void write(HttpServletResponse response,
                             InputStream inputStream,
                             String filename,
                             boolean preview,
                             Map<String, String> header) {

        AssertUtil.nonNull(inputStream, "输入数据流不能为空！");

        byte[] bytes = IoUtil.readBytes(inputStream);
        write(response, bytes, filename, preview, header);
    }
}
